var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
//please use tsc main.ts -t es6
//i hate javascript.
import Plugin from "../../lib/plugins/plugin.js";
import ChildProcess from "node:child_process";
import FileSystem from "node:fs";
import { setTimeout as SetTimeoutPromise } from "node:timers/promises";
import JsonFile from "jsonfile";
class OutputInfo {
}
class ProcessInfo {
}
var TaskType;
(function (TaskType) {
    TaskType[TaskType["PerMinute"] = 0] = "PerMinute";
    TaskType[TaskType["PerHour"] = 1] = "PerHour";
    TaskType[TaskType["PerDay"] = 2] = "PerDay";
})(TaskType || (TaskType = {}));
class Task {
}
let Processes = new Map();
let Tasks = [];
let TaskAbortController = new Map;
FileSystem.stat("tasks.json", (error, status) => {
    if (error) {
        global.logger.mark("正在创建tasks.json");
        FileSystem.writeFile("tasks.json", JSON.stringify(Tasks), error => {
            if (error)
                global.logger.error(`创建tasks.json时出现错误：${error}`);
        });
    }
    else if (!status.isFile())
        global.logger.error("tasks.json不是文件，请删除它");
    else
        JsonFile
            .readFile("tasks.json")
            .then((data) => { Tasks = data; })
            .catch((error) => { global.logger.error(error); })
            .then(() => {
            Tasks.forEach(task => {
                let abortController = new AbortController();
                let signal = abortController.signal;
                TaskAbortController.set(task.Name, abortController);
                let waitTime;
                switch (task.Type) {
                    case TaskType.PerMinute:
                        waitTime = 60 * 1000;
                        break;
                    case TaskType.PerHour:
                        waitTime = 60 * 60 * 1000;
                        break;
                    case TaskType.PerDay:
                        waitTime = 60 * 60 * 24 * 1000;
                        break;
                }
                let call = () => SetTimeoutPromise(waitTime, undefined, { signal })
                    .then(() => {
                    var _a, _b;
                    global.logger.mark(`定时任务${task.Name}开始`);
                    let process;
                    process = ChildProcess.spawn(task.ShellCommand, { shell: true });
                    signal.onabort = () => {
                        if (!process.kill(15))
                            process.kill(9);
                    };
                    let stdoutBuffer = "", stderrBuffer = "", hasStdout = false, hasStderr = false;
                    (_a = process.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (out) => {
                        if (hasStdout)
                            stdoutBuffer += out;
                        else {
                            hasStdout = true;
                            stdoutBuffer = out;
                            setTimeout(() => {
                                global.logger.mark(`Send to ${task.SendTarget} : ${stdoutBuffer}`);
                                global.Bot.pickFriend(task.SendTarget).sendMsg(`任务${task.Name}:stdout:\n${stdoutBuffer}`);
                                hasStdout = false, stdoutBuffer = "";
                            }, 1000);
                        }
                    });
                    (_b = process.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (out) => {
                        if (hasStderr)
                            stderrBuffer += out;
                        else {
                            hasStderr = true;
                            stderrBuffer = out;
                            setTimeout(() => {
                                global.logger.mark(`Send to ${task.SendTarget} : ${stderrBuffer}`);
                                global.Bot.pickFriend(task.SendTarget).sendMsg(`任务${task.Name}:stderr:\n${stderrBuffer}`);
                                hasStderr = false, stderrBuffer = "";
                            }, 1000);
                        }
                    });
                    global.logger.mark(`定时任务${task.Name}结束`);
                    if (!signal.aborted)
                        call();
                });
                call();
                global.logger.mark(`定时任务${task.Name}已加载`);
            });
        });
});
export class BetterRc extends Plugin {
    constructor() {
        super({
            name: '远程命令',
            dsc: '在运行bot的计算机上执行任何命令（仅限管理员，高危）',
            event: 'message',
            priority: 5000,
            rule: [
                {
                    reg: '^#执行',
                    fnc: 'StartShell',
                    permission: "master"
                },
                {
                    reg: "^#停止执行$",
                    fnc: "StopShell",
                    permission: "master"
                },
                {
                    reg: "^#输入",
                    fnc: "AddInput",
                    permission: "master"
                },
                {
                    reg: "^#重定向输出$",
                    fnc: "ChangeTarget",
                    permission: "master"
                },
                {
                    reg: "^#添加任务",
                    fnc: "AddTask",
                    permission: "master"
                },
                {
                    reg: "^#删除任务",
                    fnc: "RemoveTask",
                    permission: "master"
                }
            ],
            handler: undefined,
            namespace: undefined
        });
    }
    StartShell() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a, _b;
            if (Processes.has(this.e.user_id)) {
                this.reply("当前有未终止的进程，请发送 #停止执行 后再试。");
                return;
            }
            let process;
            let msg = this.e.msg.substring("#执行".length).trim();
            let procoutinf = new OutputInfo();
            let target = this.e.user_id;
            procoutinf.Target = this.e.group === undefined ? this.e.friend : this.e.group, procoutinf.HasOutput = false, procoutinf.Buffer = "";
            process = ChildProcess.spawn(msg, { shell: true });
            let processInfo = new ProcessInfo();
            processInfo.Process = process, processInfo.StderrInfo = Object.assign({}, procoutinf), processInfo.StdoutInfo = procoutinf;
            (_a = process.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (out) => {
                global.logger.mark(`Process crated by ${target}: stdout : ${out}`);
                if (processInfo.StdoutInfo.HasOutput)
                    processInfo.StdoutInfo.Buffer += out;
                else {
                    processInfo.StdoutInfo.HasOutput = true;
                    processInfo.StdoutInfo.Buffer = out;
                    setTimeout(() => {
                        global.logger.mark(`Send to ${processInfo.StdoutInfo.Target} : ${processInfo.StdoutInfo.Buffer}`);
                        processInfo.StdoutInfo.Target.sendMsg(msg + ":stdout:\n" + processInfo.StdoutInfo.Buffer);
                        processInfo.StdoutInfo.HasOutput = false, processInfo.StdoutInfo.Buffer = "";
                    }, 1000);
                }
            });
            (_b = process.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (out) => {
                global.logger.mark(`Process crated by ${target} : stderr : ${out}`);
                if (processInfo.StderrInfo.HasOutput)
                    processInfo.StderrInfo.Buffer += out;
                else {
                    processInfo.StderrInfo.HasOutput = true;
                    processInfo.StderrInfo.Buffer = out;
                    setTimeout(() => {
                        global.logger.mark(`Send to ${processInfo.StderrInfo.Target} : ${processInfo.StderrInfo.Buffer}`);
                        processInfo.StderrInfo.Target.sendMsg(msg + ":stderr:\n" + processInfo.StderrInfo.Buffer);
                        processInfo.StderrInfo.HasOutput = false, processInfo.StderrInfo.Buffer = "";
                    }, 1000);
                }
            });
            Processes.set(this.e.user_id, processInfo);
        });
    }
    StopShell() {
        return __awaiter(this, void 0, void 0, function* () {
            if (Processes.has(this.e.user_id)) {
                let process = Processes.get(this.e.user_id);
                Processes.delete(this.e.user_id);
                if (!(process === null || process === void 0 ? void 0 : process.Process.kill(15))) {
                    this.reply("kill -15失败，正在尝试使用kill -9");
                    process === null || process === void 0 ? void 0 : process.Process.kill(9);
                }
                this.reply("进程已终止，返回代码为" + (process === null || process === void 0 ? void 0 : process.Process.exitCode));
            }
            else {
                this.reply("当前没有进程。");
            }
        });
    }
    AddInput() {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            if (Processes.has(this.e.user_id)) {
                let process = Processes.get(this.e.user_id);
                let msg = this.e.msg.substring("#输入 ".length).toString() + "\n";
                (_a = process === null || process === void 0 ? void 0 : process.Process.stdin) === null || _a === void 0 ? void 0 : _a.write(msg);
            }
            else {
                this.reply("当前没有进程。");
            }
        });
    }
    ChangeTarget() {
        return __awaiter(this, void 0, void 0, function* () {
            if (Processes.has(this.e.user_id)) {
                let procecss = Processes.get(this.e.user_id);
                if (procecss !== undefined) {
                    procecss.StderrInfo.Target = this.e.group === undefined ? this.e.friend : this.e.group;
                    procecss.StdoutInfo.Target = this.e.group === undefined ? this.e.friend : this.e.group;
                    return;
                }
            }
            this.reply("当前没有进程。");
        });
    }
    SaveFile() {
        global.logger.mark("正在保存文件......");
        JsonFile.writeFile("tasks.json", Tasks, (error) => {
            if (error) {
                global.logger.error(error);
                this.reply(`保存文件时出现错误：${error}`);
            }
        });
    }
    AddTask() {
        return __awaiter(this, void 0, void 0, function* () {
            let input = this.e.msg.match("(?:^#添加任务 )([^ ]+) ([^ ]+) ([^\r]+)");
            let task = new Task();
            switch (input[1]) {
                case "每分钟":
                case "每分":
                    task.Type = TaskType.PerMinute;
                    break;
                case "每小时":
                case "每时":
                    task.Type = TaskType.PerHour;
                    break;
                case "每天":
                    task.Type = TaskType.PerDay;
                    break;
                default:
                    this.reply("任务类型错误！");
                    return;
            }
            if (TaskAbortController.has(input[2])) {
                this.reply("任务重复！");
                return;
            }
            task.Name = input[2], task.ShellCommand = input[3], task.SendTarget = this.e.user_id;
            Tasks.push(task);
            this.SaveFile();
            let abortController = new AbortController();
            let signal = abortController.signal;
            TaskAbortController.set(task.Name, abortController);
            let waitTime;
            switch (task.Type) {
                case TaskType.PerMinute:
                    waitTime = 60 * 1000;
                    break;
                case TaskType.PerHour:
                    waitTime = 60 * 60 * 1000;
                    break;
                case TaskType.PerDay:
                    waitTime = 60 * 60 * 24 * 1000;
                    break;
            }
            let call = () => SetTimeoutPromise(waitTime, undefined, { signal })
                .then(() => {
                var _a, _b;
                global.logger.mark(`定时任务${task.Name}开始`);
                let process;
                process = ChildProcess.spawn(task.ShellCommand, { shell: true });
                signal.onabort = () => {
                    if (!process.kill(15))
                        process.kill(9);
                };
                let stdoutBuffer = "", stderrBuffer = "", hasStdout = false, hasStderr = false;
                (_a = process.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (out) => {
                    if (hasStdout)
                        stdoutBuffer += out;
                    else {
                        hasStdout = true;
                        stdoutBuffer = out;
                        setTimeout(() => {
                            global.logger.mark(`Send to ${task.SendTarget} : ${stdoutBuffer}`);
                            global.Bot.pickFriend(task.SendTarget).sendMsg(`任务${task.Name}:stdout:\n${stdoutBuffer}`);
                            hasStdout = false, stdoutBuffer = "";
                        }, 1000);
                    }
                });
                (_b = process.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (out) => {
                    if (hasStderr)
                        stderrBuffer += out;
                    else {
                        hasStderr = true;
                        stderrBuffer = out;
                        setTimeout(() => {
                            global.logger.mark(`Send to ${task.SendTarget} : ${stderrBuffer}`);
                            global.Bot.pickFriend(task.SendTarget).sendMsg(`任务${task.Name}:stderr:\n${stderrBuffer}`);
                            hasStderr = false, stderrBuffer = "";
                        }, 1000);
                    }
                });
                global.logger.mark(`定时任务${task.Name}结束`);
                if (!signal.aborted)
                    call();
            });
            call();
            global.logger.mark(`定时任务${task.Name}已加载`);
        });
    }
    RemoveTask() {
        return __awaiter(this, void 0, void 0, function* () {
            let taskName = this.e.msg.match("(?:^#删除任务 )([^ ]+)")[1];
            if (!TaskAbortController.has(taskName)) {
                this.reply("任务不存在！");
                return;
            }
            let abortController = TaskAbortController.get(taskName);
            TaskAbortController.delete(taskName);
            abortController === null || abortController === void 0 ? void 0 : abortController.abort();
            Tasks = Tasks.filter(task => task.Name != taskName);
            this.SaveFile();
            global.logger.info(`任务${taskName}已经删除`);
        });
    }
}
